using System.Linq;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace FShaderInspector
{
    /// <summary> 抽屉基类 </summary>
    public class FMaterialPropertyDrawer : MaterialPropertyDrawer
    {
        /// <summary> ShaderGUI 检视面板 </summary>
        protected FShaderGUI FShaderGUI;

        /// <summary> Shader 宏 </summary>
        protected string keyword;

        /// <summary> 标签等级 </summary>
        protected int level;

        /// <summary> 标签存储 key </summary>
        protected string labelKey;

        /// <summary> 当前第一个材质 </summary>
        Material _material;

        /// <summary> 选择的材质组 </summary>
        Material[] _materials;

        /// <summary> 属性 </summary>
        MaterialProperty _prop;

        public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor)
        {
            // --- 初始化
            FShaderGUI = editor.customShaderGUI as FShaderGUI;
            if (FShaderGUI == null)
                return;

            _material = (Material)editor.target;
            _materials = editor.targets.Cast<Material>().ToArray();
            _prop = prop;

            if (FShaderGUI.LogPropTypeError(prop," Select / Enable / Foldout "))
                return;

            // --- 刷新宏状态
            foreach (var mat in _materials)
            {
                var oldState = IsKeywordEnabled(mat);
                var newState = GetMatFloatAsBool(mat);

                if (oldState == newState)
                    continue;

                if (newState)
                    FShaderGUI.TryEnableKeyword(mat, keyword);
                else
                    FShaderGUI.TryDisableKeyword(mat, keyword);
            }

            // --- 获取 EditorPrefs 记录
            labelKey = EditorCache.instance.GetPropertyKey(editor.target, prop.name);

            // --- 限制最大 level 在 1-3 之间 所有折叠页只有3级
            level = Mathf.Clamp(level, 1, 3);
        }

        public override float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor) => -2f;

        /// <summary> 是否启用关键字 </summary>
        /// <param name="mat">材质球</param>  <returns>是否开启</returns>
        protected bool IsKeywordEnabled(Material mat = null)
        {
            var targetMaterial = mat ? mat : _material;
            return targetMaterial.IsKeywordEnabled(keyword);
        }

        /// <summary> 设置折页的展开状态 </summary>
        /// <param name="open">打开</param>
        protected void SetFoldoutState(bool open)
        {
            // 保存当前的启用状态至EditorPrefs
            EditorCache.instance.SetKey(labelKey, open);

            // 无混合属性值 && 宏为启用时，才进行折页逻辑处理
            var applying = !_prop.hasMixedValue && GetPropFloatAsBool();
            FShaderGUI.isOpen = applying && open;
        }

        /// <summary> 根据材质球的 float 获取 bool </summary>
        /// <param name="mat">材质球</param> <returns>bool</returns>
        protected bool GetMatFloatAsBool(Material mat) => (int)mat.GetFloat(_prop.name) == 1;

        /// <summary> 根据属性的 float 获取 bool </summary>
        /// <returns>bool</returns>
        protected bool GetPropFloatAsBool() => (int)_prop.floatValue == 1;

        /// <summary> 根据 bool 设置属性的float </summary>
        /// <param name="enable">启用</param>
        protected void SetPropBoolAsFloat(bool enable)
        {
            MaterialEditor.BeginProperty(_prop);
            _prop.floatValue = enable ? 1 : 0;
            MaterialEditor.EndProperty();
        }

        /// <summary> 混合折页 </summary>
        /// <returns>bool</returns>
        protected bool HasMixedFoldout()
        {
            //获取初始第一个状态
            var startState = GetFoldoutStateForTarget(_prop.targets[0]);

            // 遍历从第二个目标开始的所有目标，比较状态是否一致
            for (var i = 1; i < _prop.targets.Length; i++)
            {
                if (GetFoldoutStateForTarget(_prop.targets[i]) != startState)
                    return true;
            }

            return false;
        }

        /// <summary> 获取目标的折叠状态 </summary>
        /// <param name="target">目标对象</param> <returns>bool</returns>
        protected bool GetFoldoutStateForTarget(Object target)
        {
            var key = EditorCache.instance.GetPropertyKey(target, _prop.name);
            return EditorCache.instance.GetKey(key);
        }

        /// <summary> 获取折页图标 </summary>
        /// <param name="invert">反转图标状态</param> <param name="hasMixedFold">混乱的折叠</param> <returns>GUIContent图标对象</returns>
        protected GUIContent GetFoldoutIcon(bool invert = false, bool hasMixedFold = false)
        {
            const string iconFoldoutMixed = "d_IN_foldout";
            const string iconVerticalSplit = "VerticalSplit";
            const string iconOn = "IN foldout on";
            const string iconOff = "d_IN_foldout";

            // 不同的开启状态图标
            if (_prop.hasMixedValue)
                return EditorGUIUtility.IconContent(iconFoldoutMixed);

            // 不同的折叠状态图标
            if (hasMixedFold)
                return EditorGUIUtility.IconContent(iconVerticalSplit);

            // 正常获取图标
            var state = EditorCache.instance.GetKey(labelKey);

            string iconKey;
            if (invert)
                iconKey = state ? iconFoldoutMixed : iconOn;
            else
                iconKey = state ? iconOn : iconOff;

            return EditorGUIUtility.IconContent(iconKey);
        }
    }
}